package seckill

import (
	"context"
	"fmt"
	"goods_web/rabbitmq"
	"goods_web/redisConn"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/micro/go-micro/v2/client/grpc"
	seckill "goods_product_srv/proto/seckill"
	// seckillImp "goods_seckill_srv/proto/seckill"
	"goods_web/utils"
	"net/http"
)

// 活动列表
func GetSeckillList(c *gin.Context) {
	// 获取参数
	currentPage := c.DefaultQuery("currentPage", "1")
	pageSize := c.DefaultQuery("pageSize", "10")

	// 调用服务
	client := grpc.NewClient()
	seckillsService := seckill.NewSeckillsService("go.micro.service.goods_product_srv", client)
	seckillsResponse, err := seckillsService.SeckillsList(context.Background(), &seckill.SeckillsRequest{
		CurrentPage: utils.StrToInt32(currentPage),
		PageSize:    utils.StrToInt32(pageSize),
	})

	if err != nil {
		c.JSON(http.StatusOK, gin.H{
			"msg": seckillsResponse.Msg,
			"code": seckillsResponse.Code,
		})
	}else {
		c.JSON(http.StatusOK, gin.H{
			"code": seckillsResponse.Code,
			"msg": seckillsResponse.Msg,
			"seckills": seckillsResponse.Seckills,
			"total": seckillsResponse.Total,
			"current_page": seckillsResponse.Current,
			"page_size": seckillsResponse.PageSize,
		})
	}
}


// 获取所有的商品
func GetProducts(c *gin.Context) {
	// 调用服务
	client := grpc.NewClient()
	productsService := seckill.NewSeckillsService("go.micro.service.goods_product_srv", client)
	productsResponse, err := productsService.GetProducts(context.Background(), &seckill.ProductRequest{})

	if err != nil {
		c.JSON(http.StatusOK, gin.H{
			"msg": "没有查询到商品",
			"code": 500,
		})
	}

	c.JSON(http.StatusOK, gin.H{
		"code": productsResponse.Code,
		"msg": productsResponse.Msg,
		"products": productsResponse.Products,
	})
}

// 添加活动
func AddSeckill(c *gin.Context)  {
	// 接收参数
	name := c.PostForm("name")
	price := c.PostForm("price")
	num := c.PostForm("num")
	pid := c.PostForm("pid")
	startTime := c.PostForm("start_time")
	endTime := c.PostForm("end_time")

	client := grpc.NewClient()
	newSeckillsService := seckill.NewSeckillsService("go.micro.service.goods_product_srv", client)
	response, _ := newSeckillsService.SecillsAdd(context.TODO(), &seckill.SeckillsAddRequest{
		Name:      name,
		Price:     utils.StrToFloat32(price),
		Num:       utils.StrToInt32(num),
		ProductId: utils.StrToInt32(pid),
		StartTime: startTime,
		EndTime:   endTime,
	})

	c.JSON(http.StatusOK, gin.H{
		"code": response.Code,
		"msg": response.Msg,
	})
}

// 编辑活动显示数据
func ToEditSeckill(c *gin.Context) {
	// 接收参数
	id := c.Query("id")
	// fmt.Println(id)
	// 校验参数
	if id == "" {
		c.JSON(http.StatusOK, gin.H{
			"code": 403,
			"msg": "编辑失败，请刷新页面",
		})
	}
	// 调用服务查询数据
	client := grpc.NewClient()
	newSeckillsService := seckill.NewSeckillsService("go.micro.service.goods_product_srv", client)
	response, err := newSeckillsService.ToEditSeckill(context.TODO(), &seckill.ToEditSeckillRequest{
		Id: utils.StrToInt32(id),
	})
	if err != nil {
		c.JSON(http.StatusOK, gin.H{
			"code": response.Code,
			"msg": response.Msg,
		})
	}
	c.JSON(http.StatusOK, gin.H{
		"code": response.Code,
		"msg": response.Msg,
		"seckill": response.Seckills,
		"products_no": response.ProductsNo,
	})

}

// 编辑活动数据
func DoEditSeckill(c *gin.Context) {
	// 类似添加活动
	// 接收参数
	id := c.PostForm("id")
	name := c.PostForm("name")
	price := c.PostForm("price")
	num := c.PostForm("num")
	pid := c.PostForm("pid")
	startTime := c.PostForm("start_time")
	endTime := c.PostForm("end_time")

	client := grpc.NewClient()
	newSeckillsService := seckill.NewSeckillsService("go.micro.service.goods_product_srv", client)
	response, _ := newSeckillsService.DoEditSeckill(context.TODO(), &seckill.DoEditSeckillRequest{
		Id:        utils.StrToInt32(id),
		Name:      name,
		Price:     utils.StrToFloat32(price),
		Num:       utils.StrToInt32(num),
		ProductId: utils.StrToInt32(pid),
		StartTime: startTime,
		EndTime:   endTime,
	})

	c.JSON(http.StatusOK, gin.H{
		"code": response.Code,
		"msg": response.Msg,
	})
}

// 删除活动
func DeleteSeckill(c *gin.Context) {
	id := c.PostForm("id")

	client := grpc.NewClient()
	newSeckillsService := seckill.NewSeckillsService("go.micro.service.goods_product_srv", client)
	response, _ := newSeckillsService.DeleteSeckill(context.TODO(), &seckill.DeleteSeckillRequest{
		Id: utils.StrToInt32(id),
	})

	c.JSON(http.StatusOK, gin.H{
		"code": response.Code,
		"msg": response.Msg,
	})
	
}

/*
前端展示
 */
func FrontGetSeckillList(c *gin.Context) {
	// 接收参数
	currentPage := c.Query("currentPage")
	pageSize := c.Query("pageSize")
	// fmt.Println(currentPage, pageSize)

	client := grpc.NewClient()
	newSeckillsService := seckill.NewSeckillsService("go.micro.service.goods_product_srv", client)
	frontSeckillsList, _ := newSeckillsService.FrontSeckillsList(context.TODO(), &seckill.FrontSeckillsRequest{
		CurrentPage: utils.StrToInt32(currentPage),
		PageSize:    utils.StrToInt32(pageSize),
	})

	//if err != nil {
	//	c.JSON(http.StatusOK, gin.H{
	//		"code": frontSeckillsList.Code,
	//		"msg": frontSeckillsList.Msg,
	//	})
	//}

	for _, v := range frontSeckillsList.SeckillList {
		v.Pic = utils.Img2Base64(v.Pic)
	}

	c.JSON(http.StatusOK, gin.H{
		"code": frontSeckillsList.Code,
		"msg": frontSeckillsList.Msg,
		"seckill_list": frontSeckillsList.SeckillList,
		"current": frontSeckillsList.CurrentPage,
		"page_size": frontSeckillsList.PageSize,
		"total_page": frontSeckillsList.TotalPage,
	})

}

/*
前端详细活动
 */
func FrontSeckillDetail(c *gin.Context) {
	// 接收参数
	id := c.Query("id")

	client := grpc.NewClient()
	newSeckillsService := seckill.NewSeckillsService("go.micro.service.goods_product_srv", client)
	res, err := newSeckillsService.FrontSeckillsDetail(context.TODO(), &seckill.DetailRequest{
		Id: utils.StrToInt32(id),
	})

	if err != nil {
		c.JSON(http.StatusOK, gin.H{
			"code": res.Code,
			"msg": res.Msg,
		})
	}
	//resSeckill := make(map[string]string, 0)
	//resSeckill["id"] = res.Id
	c.JSON(http.StatusOK, gin.H{
		"code": res.Code,
		"msg": res.Msg,
		"id": res.Id,
		"p_price": res.NewPrice,
		"num": res.Num,
		"unit": res.Unit,
		"start_time":res.StartTime,
		"end_time": res.EndTime,
		"pic": utils.Img2Base64(res.Pic),
		"name": res.Name,
		"pdesc": res.Desc,
	})
}


// 秒杀实现
func Seckill(c *gin.Context) {
	id := c.PostForm("id")
	// fmt.Println(id)

	// 从token中取出username
	frontUserEmail, exists := c.Get("front_user_name")
	if !exists {
		c.JSON(http.StatusOK, gin.H{
			"code": 400,
			"msg": "Token错误",
		})
	}

	/*
	把消息发到队列
	 */
	configMQ := rabbitmq.QueueAndExchange{
		QueueName:    "orderQueue",
		ExchangeName: "orderExchange",
		ExchangeType: "direct",
		ExchangeKey:  "orderKey",
	}

	mq := rabbitmq.NewRabbitMQ(configMQ)
	mq.ConnMQ()
	mq.CreateChannel()
	defer mq.CloseMQ()
	defer mq.CloseChannel()

	data := map[string]interface{}{
		"email": frontUserEmail,
		"id": id,
	}

	/*
		解决用户恶意重复点击购买问题
		使用缓存解决
		发送消息前判断缓存中有没有用户信息
		如果没有便发送消息，并加入缓存
		如果有返回不能重复下单
	*/

	// 先判断缓存中有没有
	_, err := redisConn.RedisDb.Get("repeat" + frontUserEmail.(string)).Result()
	// fmt.Println(res, err)
	if err == nil {   // err == nil 表示成功获取到数据
	    // 直接返回
		c.JSON(http.StatusOK, gin.H{
			"code": 500,
			"msg": "你已下单，请勿重复点击",
		})
		return
	}

	// 否则把消息加入队列
	mq.PublishMsg(utils.MapToString(data))


	// 再加入缓存   10分钟内不能再次点击
	_, redisErr := redisConn.RedisDb.Set("repeat"+frontUserEmail.(string), 1, 600*time.Second).Result()
	if redisErr != nil {
		c.JSON(http.StatusOK, gin.H{
			"code": 500,
			"msg": "服务器错误",
		})
		return
	}

	// 调用服务
	//client := grpc.NewClient()
	//seckillService := seckillImp.NewSeckillService("go.micro.service.goods_seckill_srv", client)
	//response, _ := seckillService.Seckill(context.TODO(), &seckillImp.SeckillRequest{
	//	Id: utils.StrToInt32(id),
	//	UserEmail:frontUserEmail.(string),
	//})

	c.JSON(http.StatusOK, gin.H{
		"code": 500,
		"msg": "下单中，请稍后",
	})
}

// 获取响应结果
func GetResult(c *gin.Context) {
	// 获取email
	value, exists := c.Get("front_user_name")
	
	if exists {
		// 查询redis
		result, err := redisConn.RedisDb.Get(value.(string)).Result()
		fmt.Println("============================")
		fmt.Println(result)

		if err == nil {     // err == nil 表示成功获取到数据

			resultMap := utils.StringToMap(result)
			c.JSON(http.StatusOK, gin.H{
				"code": 200,
				"msg": resultMap["msg"],
			})
			return
		}
		c.JSON(http.StatusOK, gin.H{
			"code": 500,
		})
		return
	}
}

